/*
 * music.c
 *
 *  Created on: Apr 16, 2015
 *      Author: mxw
 */
#include <music.h>
#include <S3C2440addr.h>
#include <timer.h>
#include <commlib.h>
#include <LedDrv.h>

struct MusHead_t {
    struct Music_t* head;
    int             toneCnt;
    char*           name;
};
#include "mu_data.inc"

void on_time_out_mute(unsigned short tid);
void on_time_out_sing(unsigned short tid);

/*         c1                 c2
 *  0 0 0 0  0 0 0 0   0 0 0 0  0 0 0 0
 *        - -------------- ------------
 *        |      |_yingao       |___shichang
 *        |
 *        |_kongxi
 * */
void Buzzer_Freq_Set(unsigned int freq) {
    rGPBCON &= ~3;          //set GPB0 as tout0, pwm output
    rGPBCON |= 2;

    rTCFG0 &= ~0xff;
    rTCFG0 |= 15;           //prescaler = 15+1
    rTCFG1 &= ~0xf;
    rTCFG1 |= 2;            //mux = 1/8
    //rTCNTB0 = (PCLK>>7)/freq;
    rTCNTB0 = freq;
    rTCMPB0 = rTCNTB0 >> 1;   // 50%
    rTCON &= ~0x1f;
    rTCON |= 0xb;           //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0
    rTCON &= ~2;            //clear manual update bit
}
void Buzzer_Stop( void ) {
    rGPBCON &= ~3;          //set GPB0 as output
    rGPBCON |= 1;
    rGPBDAT &= ~1;
}

unsigned int freqTab[] = { //count:1+5*7=36 [0,35]
        0,//静止符
        1953, 1953, 1953, 1953, 1953, 1953, 1953,   //低二 1,2,3,4,5,6,7
        2981, 2657, 2367, 2232, 1992, 1775, 1581,    //低一 1,2,3,4,5,6,7
        1490, 1365, 1183, 1119, 996,  887,  790,       //常音 1,2,3,4,5,6,7
        746,  665,  592,  559,  498,  444,  395,           //高一 1,2,3,4,5,6,7
        373,  332,  296,  279,  249,  221,  197           //高二 1,2,3,4,5,6,7
};

static int g_cur_idx = 0;
static int g_end_idx = 0;

static char g_yingaoIdx = 0;
static char g_shichang = 0;
static int g_kongxi = 0;





//struct MusHead_t allMus[] = {
//    {myMus_OnlyCareYou, sizeof(myMus_OnlyCareYou) / sizeof(struct Music_t), "我只在乎你"},
//    {myMus_YellowHill, sizeof(myMus_YellowHill) / sizeof(struct Music_t), "黄土高坡"},
//    {myMus_HappySlave, sizeof(myMus_HappySlave) / sizeof(struct Music_t), "翻身农奴把歌唱"},
//};

#define ST_SING_STOP            (0)
#define ST_PRE_MUTE             (1)
#define ST_SINGING              (2)
static unsigned char _music_st = ST_SING_STOP;
static unsigned short _tid_mute = 0;
static unsigned short _tid_sing = 0;


int isum = 0;

void init_music() {
    _music_st = ST_SING_STOP;
    _tid_mute = get_new_timer(on_time_out_mute);
    _tid_sing = get_new_timer(on_time_out_sing);
}

void request_to_stop() {
    switch(_music_st) {
    case ST_SING_STOP:
        break;
    case ST_PRE_MUTE:
    case ST_SINGING:
        Buzzer_Stop();
        set_led(LED_ALL, LED_OFF);
        stop_timer(_tid_mute);
        stop_timer(_tid_sing);
        _music_st = ST_SING_STOP;
        break;
    default:
        ;
        break;
    }
}

void on_time_out_mute(unsigned short tid) {
    switch(_music_st) {
    case ST_SING_STOP:
        break;
    case ST_PRE_MUTE:
        stop_timer(_tid_mute);
        if (g_cur_idx >= g_end_idx) {
            _music_st = ST_SING_STOP;
            return;
        }

        isum = ((myMus_OnlyCareYou[g_cur_idx].c1 << 8) | myMus_OnlyCareYou[g_cur_idx].c2);
        printf(myMus_OnlyCareYou[g_cur_idx].geci);
        ++g_cur_idx;

        g_yingaoIdx = ((isum >> 6) & 0x3F);
        g_shichang = (isum & 0x3F);
        g_kongxi = ((isum >> 12) & 0x1);
        Buzzer_Freq_Set(freqTab[(int)g_yingaoIdx]);
        set_led_by_low_4bit(g_yingaoIdx);
        start_timer(_tid_sing, g_shichang * 40);
        _music_st = ST_SINGING;
        break;
    case ST_SINGING:
        break;
    default:
        ;
        break;
    }
}

void on_time_out_sing(unsigned short tid) {
    switch(_music_st) {
    case ST_SING_STOP:
        break;
    case ST_PRE_MUTE:
        break;
    case ST_SINGING:
        stop_timer(_tid_sing);
        if (g_kongxi) {
            Buzzer_Stop();
            set_led(LED_ALL, LED_OFF);
            start_timer(_tid_mute, 20);
            _music_st = ST_PRE_MUTE;
        } else {
            if (g_cur_idx >= g_end_idx) {
                _music_st = ST_SING_STOP;
                Buzzer_Stop();
                set_led(LED_ALL, LED_OFF);
                return;
            }
        
            isum = ((myMus_OnlyCareYou[g_cur_idx].c1 << 8) | myMus_OnlyCareYou[g_cur_idx].c2);
            printf(myMus_OnlyCareYou[g_cur_idx].geci);
            ++g_cur_idx;

            g_yingaoIdx = ((isum >> 6) & 0x3F);
            g_shichang = (isum & 0x3F);
            g_kongxi = ((isum >> 12) & 0x1);
            Buzzer_Freq_Set(freqTab[(int)g_yingaoIdx]);
            set_led_by_low_4bit(g_yingaoIdx);
            start_timer(_tid_sing, g_shichang * 40);
        }
        break;
    default:
        ;
        break;
    }
}

void new_muisc_go() {
    g_cur_idx = 0;
    g_end_idx = sizeof(myMus_OnlyCareYou) / sizeof(struct Music_t);

    isum = ((myMus_OnlyCareYou[g_cur_idx].c1 << 8) | myMus_OnlyCareYou[g_cur_idx].c2);
    printf(myMus_OnlyCareYou[g_cur_idx].geci);


    g_yingaoIdx = ((isum >> 6) & 0x3F);
    g_shichang = (isum & 0x3F);
    g_kongxi = ((isum >> 12) & 0x1);

    Buzzer_Freq_Set(freqTab[(int)g_yingaoIdx]);
    set_led_by_low_4bit(g_yingaoIdx);
    start_timer(_tid_sing, g_shichang * 40); //timeout callback: on_time_out_sing

    ++g_cur_idx;
    _music_st = ST_SINGING;
}
